home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / plnk081.zip / pilot-link.0.8.1 / libsock / unixserial.c < prev    next >
C/C++ Source or Header  |  1997-06-29  |  8KB  |  401 lines

  1. /* unixserial.c: tty line interface code for Pilot serial comms under UNIX
  2.  *
  3.  * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski.
  4.  * This is free software, licensed under the GNU Public License V2.
  5.  * See the file COPYING for details.
  6.  */
  7.  
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <stdio.h>
  11. #include "pi-source.h"
  12. #include "pi-socket.h"
  13. #include "pi-serial.h"
  14. #include "pi-slp.h"
  15. #include "pi-syspkt.h"
  16. #include "pi-padp.h"
  17.  
  18. /* if this is running on a NeXT system... */
  19. #ifdef NeXT
  20. #include <sys/uio.h>
  21. #include <sys/time.h>
  22. #include <unistd.h>
  23. #include <sys/file.h>
  24. #include <fcntl.h>
  25. #endif
  26.  
  27. #ifdef HAVE_SYS_IOCTL_COMPAT_H
  28. #include <sys/ioctl_compat.h>
  29. #endif
  30.  
  31. #ifdef HAVE_SYS_SELECT_H
  32. #include <sys/select.h>
  33. #endif
  34.  
  35. #ifndef SGTTY
  36.  
  37. #ifndef HAVE_CFMAKERAW
  38. #define cfmakeraw(ptr) (ptr)->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\
  39.                      |IGNCR|ICRNL|IXON);\
  40.                        (ptr)->c_oflag &= ~OPOST;\
  41.                        (ptr)->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);\
  42.                        (ptr)->c_cflag &= ~(CSIZE|PARENB);\
  43.                        (ptr)->c_cflag |= CS8
  44. #endif
  45.  
  46. #ifndef HAVE_CFSETSPEED
  47. #if defined(HAVE_CFSETISPEED) && defined(HAVE_CFSETOSPEED)
  48. #define cfsetspeed(t,speed) \
  49.   (cfsetispeed(t,speed) || cfsetospeed(t,speed))
  50. #else
  51. static int cfsetspeed(struct termios * t,int speed) {
  52. #ifdef HAVE_TERMIOS_CSPEED
  53.   t->c_ispeed=speed;
  54.   t->c_ospeed=speed;
  55. #else
  56.   t->c_cflag|=speed;
  57. #endif
  58.   return 0;
  59. }
  60. #endif
  61. #endif
  62.  
  63. #endif /*SGTTY*/
  64.  
  65. static int calcrate(int baudrate) {
  66. #ifdef B300
  67.   if(baudrate == 300) return B300;
  68. #endif
  69. #ifdef B1200
  70.   if(baudrate == 1200) return B1200;
  71. #endif
  72. #ifdef B2400
  73.   if(baudrate == 2400) return B2400;
  74. #endif
  75. #ifdef B4800
  76.   if(baudrate == 4800) return B4800;
  77. #endif
  78. #ifdef B9600
  79.   if(baudrate == 9600) return B9600;
  80. #endif
  81. #ifdef B19200
  82.   else if(baudrate == 19200) return B19200;
  83. #endif
  84. #ifdef B38400
  85.   else if(baudrate == 38400) return B38400;
  86. #endif
  87. #ifdef B57600
  88.   else if(baudrate == 57600) return B57600;
  89. #endif
  90. #ifdef B115200
  91.   else if(baudrate == 115200) return B115200;
  92. #endif
  93. #ifdef B230400
  94.   else if(baudrate == 230400) return B230400;
  95. #endif
  96. #ifdef B460800
  97.   else if(baudrate == 460800) return B460800;
  98. #endif
  99.   else {
  100.     printf("Unable to set baud rate %d\n", baudrate);
  101.     abort(); /* invalid baud rate */
  102.   }
  103. }
  104.  
  105. #ifndef O_NONBLOCK
  106. # define O_NONBLOCK 0
  107. #endif
  108.  
  109. static int s_changebaud(struct pi_socket *ps);
  110. static int s_close(struct pi_socket *ps);
  111. static int s_write(struct pi_socket *ps);
  112. static int s_read(struct pi_socket *ps, int timeout);
  113.  
  114. int pi_serial_open(struct pi_socket *ps, struct pi_sockaddr * addr, int addrlen)
  115. {
  116.   char * tty = addr->pi_device;
  117.  
  118.   int i;
  119. #ifndef SGTTY
  120.   struct termios tcn;
  121. #else
  122.   struct sgttyb tcn;
  123. #endif
  124.  
  125.   if ((!tty) || !strlen(tty))
  126.     tty = getenv("PILOTPORT");
  127.   if (!tty)
  128.     tty = "<Null>";
  129.  
  130.   if ((ps->mac->fd = open(tty, O_RDWR | O_NONBLOCK )) == -1) {
  131.     return -1;     /* errno already set */
  132.   }
  133.  
  134.   if (!isatty(ps->mac->fd)) {
  135.     close(ps->mac->fd);
  136.     errno = EINVAL;
  137.     return -1;
  138.   }
  139.  
  140. #ifndef SGTTY
  141.   /* Set the tty to raw and to the correct speed */
  142.   tcgetattr(ps->mac->fd,&tcn);
  143.  
  144.   ps->tco = tcn;
  145.  
  146.   tcn.c_oflag = 0;
  147.   tcn.c_iflag = IGNBRK | IGNPAR;
  148.  
  149.   tcn.c_cflag = CREAD | CLOCAL | CS8;
  150.   
  151.   (void)cfsetspeed(&tcn, calcrate(ps->rate));
  152.  
  153.   tcn.c_lflag = NOFLSH;
  154.  
  155.   cfmakeraw(&tcn);
  156.  
  157.   for(i=0;i<16;i++) tcn.c_cc[i]=0;
  158.  
  159.   tcn.c_cc[VMIN] = 1;
  160.   tcn.c_cc[VTIME] = 0;
  161.   
  162.   tcsetattr(ps->mac->fd,TCSANOW,&tcn);
  163. #else
  164.   /* Set the tty to raw and to the correct speed */
  165.   ioctl(ps->mac->fd, TIOCGETP, &tcn);
  166.  
  167.   ps->tco = tcn;
  168.  
  169.   tcn.sg_flags = RAW;
  170.   tcn.sg_ispeed = calcrate(ps->rate);
  171.   tcn.sg_ospeed = calcrate(ps->rate);
  172.   
  173.   ioctl(ps->mac->fd, TIOCSETN, &tcn);
  174. #endif
  175.  
  176.   if ((i = fcntl(ps->mac->fd, F_GETFL, 0))!=-1) {
  177.     i &= ~O_NONBLOCK;
  178.     fcntl(ps->mac->fd, F_SETFL, i);
  179.   }
  180.  
  181.   if (ps->sd) {
  182.     int orig = ps->mac->fd;
  183. #ifdef HAVE_DUP2
  184.     ps->mac->fd = dup2(ps->mac->fd, ps->sd);
  185. #else
  186. #ifdef F_DUPFD
  187.     close(ps->sd);
  188.     ps->mac->fd = fcntl(ps->mac->fd, F_DUPFD, ps->sd);
  189. #else
  190.     close(ps->sd);
  191.     ps->mac->fd = dup(ps->mac->fd); /* Unreliable */
  192. #endif
  193. #endif
  194.     if (ps->mac->fd != orig)
  195.       close(orig);
  196.   }
  197.  
  198. #ifndef NO_SERIAL_TRACE
  199.   if(ps->debuglog) {
  200.     ps->debugfd = open(ps->debuglog,O_WRONLY|O_CREAT|O_APPEND,0666);
  201.     /* This sequence is magic used by my trace analyzer - kja */
  202.     write(ps->debugfd, "\0\1\0\0\0\0\0\0\0\0", 10);
  203.   }
  204. #endif
  205.  
  206.   ps->serial_close = s_close;
  207.   ps->serial_read = s_read;
  208.   ps->serial_write = s_write;
  209.   ps->serial_changebaud = s_changebaud;
  210.   
  211.   return ps->mac->fd;
  212. }
  213.  
  214. /* Linux versions "before 2.1.8 or so" fail to flush hardware FIFO on port close */
  215. #ifdef linux
  216. # ifndef LINUX_VERSION_CODE
  217. #  include <linux/version.h>
  218. # endif
  219. # ifndef LINUX_VERSION_CODE
  220. #  define sleeping_beauty
  221. # else
  222. #  if (LINUX_VERSION_CODE < 0x020108)
  223. #   define sleeping_beauty
  224. #  endif
  225. # endif
  226. #endif
  227.  
  228. /* Unspecified NetBSD versions fail to flush hardware FIFO on port close */
  229. #ifdef __NetBSD__
  230. # define sleeping_beauty
  231. #endif
  232.  
  233. /* SGI IRIX fails to flush hardware FIFO on port close */
  234. #ifdef __sgi
  235. # define sleeping_beauty
  236. #endif
  237.  
  238. static int s_changebaud(struct pi_socket *ps)
  239. {
  240. #ifndef SGTTY
  241.   struct termios tcn;
  242.  
  243. #ifdef sleeping_beauty
  244.   struct timeval tv; 
  245.   tv.tv_sec = 0;
  246.   tv.tv_usec = 50000;
  247.   select(0,0,0,0, &tv);
  248. #endif
  249.  
  250.   /* Set the tty to the new speed */
  251.   tcgetattr(ps->mac->fd,&tcn);
  252.  
  253.   tcn.c_cflag =  CREAD | CLOCAL | CS8;
  254.   (void)cfsetspeed(&tcn, calcrate(ps->rate));
  255.  
  256.   tcsetattr(ps->mac->fd,TCSADRAIN,&tcn);
  257.  
  258. #ifdef sleeping_beauty
  259.   tv.tv_sec = 0;
  260.   tv.tv_usec = 50000;
  261.   select(0,0,0,0, &tv);
  262. #endif
  263.  
  264. #else
  265.   struct sgttyb tcn;
  266.  
  267.   ioctl(ps->mac->fd, TIOCGETP, &tcn);
  268.  
  269.   tcn.sg_ispeed = calcrate(ps->rate);
  270.   tcn.sg_ospeed = calcrate(ps->rate);
  271.   
  272.   ioctl(ps->mac->fd, TIOCSETN, &tcn);
  273. #endif
  274.  
  275.   return 0;
  276. }
  277.  
  278.  
  279.  
  280. static int s_close(struct pi_socket *ps)
  281. {
  282.   int result;
  283. #ifndef SGTTY
  284.  
  285.   tcsetattr(ps->mac->fd,TCSADRAIN, &ps->tco);
  286. #else
  287.  
  288.   ioctl(ps->mac->fd, TIOCSETP, &ps->tco);
  289.  
  290. #endif
  291.     
  292.   result = close(ps->mac->fd);
  293.   ps->mac->fd = 0;
  294.  
  295. #ifndef NO_SERIAL_TRACE
  296.   if (ps->debugfd)
  297.     close(ps->debugfd);  
  298. #endif
  299.  
  300.   return result;
  301. }
  302.  
  303. static int s_write(struct pi_socket *ps)
  304. {
  305.   struct pi_skb *skb;
  306.   int nwrote, len;
  307. #ifndef NO_SERIAL_TRACE
  308.   int i;
  309. #endif
  310.  
  311.   if (ps->txq) {
  312.     ps->busy++;
  313.  
  314.     skb = ps->txq;
  315.     ps->txq = skb->next;
  316.  
  317.     len = 0;
  318.     while (len<skb->len) {
  319.       nwrote = 0;
  320.       nwrote=write(ps->mac->fd,skb->data,skb->len);
  321.       if (nwrote<=0)
  322.         break; /* transmission failure */
  323.       len += nwrote;
  324.     }
  325. #ifndef NO_SERIAL_TRACE
  326.     if (ps->debuglog)
  327.       for (i=0;i<skb->len;i++) {
  328.         write(ps->debugfd, "2", 1);
  329.         write(ps->debugfd, skb->data+i, 1);
  330.       }
  331. #endif
  332.     ps->tx_bytes += skb->len;
  333.     free(skb);
  334.  
  335.     ps->busy--;
  336.     
  337.     return 1;
  338.   }
  339.   return 0;
  340. }
  341.  
  342. static int s_read(struct pi_socket *ps, int timeout)
  343. {
  344.   int r;
  345.   unsigned char *buf;
  346. #ifndef NO_SERIAL_TRACE
  347.   int i;
  348. #endif
  349.   fd_set ready,ready2;
  350.   struct timeval t;
  351.   
  352.   FD_ZERO(&ready);
  353.   FD_SET(ps->mac->fd, &ready);
  354.  
  355.   /* FIXME: if timeout == 0, wait forever for packet, otherwise wait till
  356.      timeout tenth-of-seconds */
  357.  
  358.   pi_serial_flush(ps);              /* We likely want to be in sync with tx */
  359.   if (!ps->mac->expect) slp_rx(ps);  /* let SLP know we want a packet */
  360.  
  361.   while (ps->mac->expect) {
  362.     buf = ps->mac->buf;
  363.  
  364.     while (ps->mac->expect) {
  365.       ready2 = ready;
  366.       t.tv_sec = timeout/10;
  367.       t.tv_usec = (timeout % 10) * 100000;
  368.       select(ps->mac->fd+1,&ready2,0,0,&t);
  369.       /* If data is available in time, read it */
  370.       if(FD_ISSET(ps->mac->fd,&ready2))
  371.         r = read(ps->mac->fd, buf, ps->mac->expect);
  372.       else
  373.       {
  374.         /* otherwise throw out any current packet and return */
  375. #ifdef DEBUG
  376.         fprintf(stderr, "Serial RX: timeout\n");
  377. #endif
  378.         ps->mac->state = ps->mac->expect = 1;
  379.         ps->mac->buf = ps->mac->rxb->data;
  380.         ps->rx_errors++;
  381.         return 0;
  382.       }
  383. #ifndef NO_SERIAL_TRACE
  384.       if (ps->debuglog)
  385.         for (i=0;i<r;i++) {
  386.           write(ps->debugfd, "1", 1);
  387.           write(ps->debugfd, buf+i, 1);
  388.         }
  389. #endif
  390.       ps->rx_bytes += r;
  391.       buf += r;
  392.       ps->mac->expect -= r;
  393.     }
  394.     slp_rx(ps);
  395.   }
  396.   return 0;
  397. }
  398.  
  399.  
  400.  
  401.